package org.abratuhi.uradar.model;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Properties;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.abratuhi.uradar.modules.URadarModuleFB;
import org.abratuhi.uradar.modules.URadarModuleRegistration;
import org.abratuhi.uradar.modules.URadarModuleSL;
import org.abratuhi.uradar.util.RequestUtil;

/**
 * 'Main' class of URadar application.
 * <p>
 * Contains the information about underlying MySQL database: hostname, port, database name, username and password.
 * <p>
 * Is responsible for:
 * <ul>
 * <li>establishing connection to MySQL database</li>
 * <li>adding/removing modules</li>
 * <li>creating instances of modules(which in their turn check, whether the tables they use are already present in database, if not -> create them), passing them a valid connection to MySQL database</li>
 * <li>redirecting requests to corresponding modules and sending responses from modules back to requester.</li>
 * </ul>
 * 
 * @author Alexei Bratuhin
 * @version 1.00
 */
@SuppressWarnings("serial")
public class URadar extends HttpServlet{
	/** Singleton instance of URadar **/
	static URadar instance;
	
	/**	Application properties. Contain data needed to connect to MySQL DB. **/
	Properties props = new Properties();
	/** Contains list of all URadar's modules up. **/
	ArrayList<URadarModule> modules = new ArrayList<URadarModule>(); 
	
	
	/**
	 * MySQL DB Attributes, used as shortcuts
	 */
	/** MySQL DB host address. 
	 * <p>
	 * Must be specified in form: 'host:port'. See .properties file for example.*/
	String host;
	/** MySQL DB name. 
	 * <p>
	 * Statndard values is: 'uradar'.*/
	String db;
	/** MySQL DB username. 
	 * <p>
	 * Standard value is: 'lindenuser'.*/
	String user;
	/** MySQL DB user password. 
	 * <p>
	 * Standard value is: 'linden'.*/
	String passwd;
	
	/**
	 * Constructor.
	 * [Part of URadar as Singleton impementation].
	 * URadar Constructor
	 * <ul>
	 * 	<li>loads properties,</li>
	 * 	<li>connects to MySQL DB</li>
	 * 	<li>inititalizes URadar modules</li>
	 * </ul>
	 */
	public URadar(){
		// load props
		loadProperties();
		
		// init registration module
		URadarModuleRegistration uradarregistration = new URadarModuleRegistration(null, null, props);
		modules.add(uradarregistration);
		
		// init Facebook module
		URadarModuleFB fb = new URadarModuleFB(null, null, props);
		addModule(fb);
		
		// init Second Life module
		URadarModuleSL sl = new URadarModuleSL(null, null, props);
		addModule(sl);
		
	}
	
	/**
	 * Get the only existing instance of URadar or create one, if none exists.
	 * [Part of URadar as Singleton implementation].
	 * @return	instance of URadar
	 */
	public static URadar getInstance(){
		if( instance == null){
			instance = new URadar();
		}
		return instance;
	}
	
	/**
	 * Forbid cloning instance of URadar.
	 * [Part of URadar as Singleton implementation].
	 */
	public Object clone() throws CloneNotSupportedException{
		throw new CloneNotSupportedException();
	}
	
	/**
	 * Add new URadar module to URadar application.
	 * @param module - URadar module to add to URadar
	 */
	public void addModule(URadarModule module){
		modules.add(module);
	}
	
	/**
	 * Remove an URadar module from URadar application.
	 * <p>
	 * Notice: Not really used yet, may be useful for future releases for managing modules remote from webform.
	 * @param module - URadar module to remove from URadar
	 */
	public void removeModule(URadarModule module){
		modules.remove(module);
	}
	
	/**
	 * Find the URadar module instance with given String name.
	 * @param modulename - String name of the module to look for
	 * @return	URadar module with corresponding modulename
	 */
	public URadarModule findModule(String modulename){
		for(int i=0; i<modules.size(); i++){
			if(modules.get(i).name.equals(modulename)){
				return modules.get(i);
			}
		}
		return null;
	}
	
	/**
	 * Load URadar application .properties file from root directory.
	 * <p>
	 * Notice: used only once in constructor, implemented for better code readability.
	 */
	private void loadProperties(){
		// load properties file
		FileInputStream fis;
		try {
			System.out.println("URadar:\tLooking for .properties file in "+new File("path.temp").getParent());
			fis = new FileInputStream("uradar.properties");
			props.load(fis);
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		// read properties
		host = props.getProperty("mysql.host");
		db = props.getProperty("mysql.db");
		user = props.getProperty("mysql.user");
		passwd = props.getProperty("mysql.passwd");
	}
	
	
	/**
	 * Forwards incoming requests to corresponding modules and sends their response back to requester.
	 * <p>
	 * If requested module wasn't found, send INVALID_MODULE_ID.
	 * <p>
	 * Prints requests and responses to System.out.
	 * @param req	-	HTTP GET Request
	 * @param res	-	HTTP GET Response
	 * @throws ServletException, IOException
	 */
	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		// init response string
		String response = new String();
		// get request string - string after '?'
		String request = req.getQueryString();
		System.out.println(request);
		// transform request string to request string
		Properties reqprops = RequestUtil.request2properties(request);
		if(reqprops == null || reqprops.isEmpty()) return;
		// get basic properties of request
		String reqmod = reqprops.getProperty("reqmodule");
		// find module to proceed request
		URadarModule moduleused = findModule(reqmod);
		if(moduleused!=null){
			// send request to corresponding module, get response
			response = moduleused.proceedRequest(reqprops);
			System.out.println("response=\""+response+"\"");
			// send response string over existing opened HTTP connection
			PrintWriter out = res.getWriter();
			out.println(response);
			out.close();
		}
		else{
			// print error message
			System.out.println("Module not found:\t"+reqmod);
			response = URadarModule.INVALID_MODULE_ID;
			// send response string over existing opened HTTP connection
			PrintWriter out = res.getWriter();
			out.println(response);
			out.close();
		}
	}
}
